/**
 * @name 纯 ini 格式读取器
 * @date 2017年3月19日 星期日
 */
package yangkv

import (
	"bufio"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
)

// Ini 结构体
type Ini struct {
	IsFromFile bool        // 来源文件
	IsFromStr  bool        // 来源字符串
	Path       string      // 文件路径名
	IniString  string      // ini 格式字符串
	Delimit    string      // 多值数组分隔符
	data       IniDataType // 解析后的数据格式
	Kv         Kv          // Kv 接口
}
type IniDataType map[string]interface{}

// ini - 解析器
type IniParser struct {
	filename string   // 文件名称
	comment  []string // 注释符列表
	content  string   // 文本内容
}

// 注释处理
func (ipser *IniParser) IsComment(value string) (bool, string) {
	if value == "" || len(value) == 0 || strings.Count(value, Ini_equSigner) == 0 {
		return true, ""
	}
	if len(ipser.comment) == 0 {
		ipser.comment = strings.Split(Ini_comment, ",")
	}
	for _, v := range ipser.comment {
		index := strings.Index(value, v)
		if index == 0 {
			return true, ""
		} else if index > 0 { // 存在行注释符，但是不在行首，清除注释内容
			return true, value[0:index]
		}
	}
	return false, value
}

// 逐行读取文件并解析
func (ipser *IniParser) ParseFile() IniDataType {
	fh, err := os.Open(ipser.filename)
	_inidata := IniDataType{}
	isMinIniFile := false // 是否为压缩ini
	minIniFileCtt := ""   // 压缩ini文本内容
	if err == nil {
		buf := bufio.NewReader(fh)
		for {
			// ?? 压缩文件区分
			line, err := buf.ReadString('\n')
			line = strings.TrimSpace(line)
			// 行处理
			if line == "" { // 空行跳过
				continue
			}

			tabSinger := regexp.MustCompile(`\s`)
			line = string(tabSinger.ReplaceAll([]byte(line), []byte("")))
			// 压缩文件检测
			if isMinIniFile || strings.Count(line, Ini_minkey) > 0 {
				if isMinIniFile == false {
					isMinIniFile = true
				} else {
					minIniFileCtt = minIniFileCtt + line
				}
				continue
			}
			iscommet, str := ipser.IsComment(line) // 注释行处理
			if iscommet {
				continue
			}
			line = str
			eqIndex := strings.Count(line, Ini_equSigner)
			key := line[0:eqIndex]
			value := line[eqIndex+1:]
			if strings.Count(line, Ini_delimiter) > 0 {
				_inidata[key] = strings.Split(line, Ini_delimiter)
			} else {
				_inidata[key] = value
			}
			if err != nil {
				break
			}
		}
	}
	if isMinIniFile && len(minIniFileCtt) > 0 {
		ipser.content = minIniFileCtt
		_inidata = ipser.IniStrParse()
	}
	return _inidata
}
func (ipers *IniParser) IniStrParse() IniDataType {
	_inidata := IniDataType{}
	content := ipers.content
	if len(content) > 0 {
		for _, v := range strings.Split(content, Ini_endSigner) {
			if strings.Count(v, Ini_equSigner) == 0 {
				continue
			}
			index := strings.Index(v, Ini_equSigner)
			key := v[0:index]
			value := v[index+1:]
			if strings.Count(v, Ini_delimiter) > 0 {
				_inidata[key] = strings.Split(value, Ini_delimiter)
			} else {
				_inidata[key] = value
			}
		}
	}
	return _inidata
}

// ini - 生成
type IniCreator struct {
	data    IniDataType // 推送数据
	Path    string      // 保存文件
	content string      // 待保存数据
}

// 普通文本
func (ictor *IniCreator) IniEncoder() {
	data := ictor.data
	if data == nil {
		ictor.content = ""
	} else {
		content := ""
		for k, v := range data {
			switch v.(type) {
			case string:
				content = content + k + Ini_equSigner + v.(string) + "\n"
			case []string:
				content = content + k + Ini_equSigner + strings.Join(v.([]string), Ini_delimiter) + "\n"
			}
		}
		ictor.content = content
	}
}

// 压缩文本
func (ictor *IniCreator) IniEncoderMin() {
	data := ictor.data
	content := Ini_minkey + " = 1\n"
	if data == nil {
		ictor.content = content
	} else {
		for k, v := range data {
			switch v.(type) {
			case string:
				content = content + k + Ini_equSigner + v.(string) + Ini_endSigner
			case []string:
				content = content + k + Ini_equSigner + strings.Join(v.([]string), Ini_delimiter) + Ini_endSigner
			}
		}
		ictor.content = content
	}
}

func (ictor *IniCreator) Save() bool {
	content := ictor.content
	pathname := ictor.Path
	error := ioutil.WriteFile(pathname, []byte(content), 0x644)
	if error != nil {
		return false
	}
	return true
}

// 设置值
func (ini *Ini) Set(key, value string) *KvSetter {
	kvster := &KvSetter{}
	_, has := ini.data[key]
	if has {
		kvster.IsUpdate = true
		kvster.IsNew = false
	} else {
		kvster.IsUpdate = false
		kvster.IsNew = true
	}
	ini.data[key] = value
	return kvster
}

// 删除值
func (ini *Ini) Del(keys ...string) []int {
	retInts := []int{}
	for _, key := range keys {
		befLen := len(ini.data)
		delete(ini.data, key)
		aftLen := len(ini.data)
		if befLen == aftLen {
			retInts = append(retInts, 1)
		} else {
			retInts = append(retInts, -1)
		}
	}
	return retInts
}

// 查询值
func (ini *Ini) Get(keys ...string) []string {
	value := []string{}
	data := ini.data
	delimiter := ini.Delimit
	for _, key := range keys {
		tmpValue := ""
		v, has := data[key]
		if has {
			switch v.(type) {
			case string:
				tmpValue = v.(string)
			case []string:
				tmpValue = strings.Join(v.([]string), delimiter)
			}
		}
		value = append(value, tmpValue)
	}
	return value
}

// 解释器-> IniDataType
func (ini *Ini) Parse() {
	if ini.IsFromFile { // 文件解析
		ipers := &IniParser{
			filename: ini.Path,
		}
		ini.data = ipers.ParseFile()
	} else if ini.IsFromStr { // 字符串解析
		ipers := &IniParser{
			content: ini.IniString,
		}
		ini.data = ipers.IniStrParse()
	}
}

// 文件保存
func (ini *Ini) Save() *IniCreator {
	ictor := &IniCreator{}
	ictor.data = ini.data
	ictor.Path = ini.Path
	return ictor
}
